
#include<iostream>
#include<cmath>


#include <iostream>
#include <cmath>


#include "Renderer.h"
#include "ObjReader.h"
#include "Window.h"
#include"Input.h"

#pragma comment( lib,"winmm.lib" )




using namespace std;

static const int windowWidth = 500;
static const int windowHeight = 500;

Renderer* device = NULL;
Camera* camera = new Camera(Transform(Vec4f(0, 0, 100), Vec4f(0, 0, 0), Vec4f(0, 0, 0)));
Mesh* curmesh = new Mesh();
Mesh* mesh = new Mesh();
Mesh* plane = new Mesh();
Vec4f transV, rotateV;
PhongShader* phongShader;
PhongShader* planeShader;
ShadowShader* shadowShader = new ShadowShader();
DepthBuffer* depthBuffer = new DepthBuffer(windowWidth * 2, windowHeight * 2);
DepthBuffer* zBuffer = new DepthBuffer(windowWidth, windowHeight);

Matrix mat;

void UpdateInput(Mesh* m);//get input
void Update(Window* window);//update window
void Render(Window* window);//render screen
void FPS(Window* window);//show fps
void Cube();//create cube
void Plane();//create plane


int main() {

	Window* window = new Window(windowWidth, windowHeight, "Test");
	device = new Renderer(window->screenHdc, windowWidth, windowHeight, camera);
	Matrix camV = camera->LookAt(camera->transform.position, Vec4f(0, 0, -1), Vec4f(0, 1, 0));

	//Matrix camP = camera->Perspective(-10, 10, 40, -120, 10, -10);
	Matrix camP = camera->Orthographic(-10, 10, 0, -120, 10, -10);
	Matrix lightP= camera->Orthographic(-10, 10, 0, -120, 10, -10);
	DirectionalLight dirLight(Vec4f(0.2, 0.2, -1), Vec4f(0, 0, 100));
	PointLight ptLight(Vec4f(5, 5, -5), 2);
	Texture* grid = new Texture();
	grid->LoadTexture("grid.bmp");
	Texture* brick = new Texture();
	brick->LoadTexture("brick.bmp");
	//phongShader = new PhongShader(PhongVert(), PhongFrag(grid, depthBuffer));
	phongShader = new PhongShader(PhongVert(), PhongFrag(grid, depthBuffer));
	phongShader->vert.camPos = camera->transform.position;
	phongShader->vert.dirLights.push_back(dirLight);
	phongShader->vert.ptLights.push_back(ptLight);
	phongShader->vert.v = camV;
	phongShader->vert.p = camP;
	phongShader->vert.lightVertical = dirLight.LookAt(Vec4f(0, 1, 0));
	phongShader->vert.lightParallel = lightP;


	shadowShader->vert.lightVertical = dirLight.LookAt(Vec4f(0, 1, 0));
	shadowShader->vert.lightParallel = lightP;

	planeShader = new PhongShader(PhongVert(), PhongFrag(brick, depthBuffer));

	planeShader->vert.camPos = camera->transform.position;
	planeShader->vert.dirLights.push_back(dirLight);
	planeShader->vert.ptLights.push_back(ptLight);
	planeShader->vert.v = camV;
	planeShader->vert.p = camP;
	planeShader->vert.lightVertical = dirLight.LookAt(Vec4f(0, 1, 0));
	planeShader->vert.lightParallel = lightP;

	Cube();
	Plane();
	ReadObj("cube.obj", mesh);
	





	device->dirLights.push_back(dirLight);
	device->ptLights.push_back(ptLight);



	
	Update(window);

	system("pause");

	return 0;




}









 void UpdateInput(Mesh* m) {
	 if (IS_KEY_DOWN('A'))
	 {
		 transV.x -= 0.01f;
	 }
	 if (IS_KEY_DOWN('D'))
	 {
		 transV.x += 0.01f;
	 }
	 if (IS_KEY_DOWN('W'))
	 {
		 transV.y += 0.01f;
	 }
	 if (IS_KEY_DOWN('S'))
	 {
		 transV.y -= 0.01f;
	 }
	 if (IS_KEY_DOWN('E'))
	 {
		 transV.z -= 0.1f;
	 }
	 if (IS_KEY_DOWN('Q'))
	 {
		 transV.z += 0.1f;
	 }
	 if (IS_KEY_DOWN('I'))
	 {
		 transV.y += 0.1f;
	 }
	 if (IS_KEY_DOWN('K'))
	 {
		 transV.y -= 0.1f;
	 }
	 if (IS_KEY_DOWN('L'))
	 {
		 transV.x += 0.5f;
	 }
	 if (IS_KEY_DOWN('J'))
	 {
		 transV.x -= 0.5f;
	 }
	 if (IS_KEY_DOWN('U'))
	 {
		 transV.z -= 0.1f;
	 }
	 if (IS_KEY_DOWN('O'))
	 {
		 transV.z += 0.1f;
	 }

	 Matrix s = mesh->GetTransform().Scale(Vec4f(1, 1, 1));
	 Matrix r = mesh->GetTransform().Rotate(rotateV);
	 Matrix t = mesh->GetTransform().Translate(transV);

	 mat = t * r * s;

	 phongShader->vert.m = mat;
	 shadowShader->vert.m = mat;
 }



 void Update(Window* window) {
	 MSG msg{ 0 };
	 while (msg.message != WM_QUIT) {
		 UpdateInput(curmesh);
		 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
			 TranslateMessage(&msg);
			 DispatchMessage(&msg);
		 }
		 else {
			 Render(window);
			 FPS(window);
		 }
	 }
 }
 void Render(Window* window) {
	 device->Clear(depthBuffer);
	 device->Clear(zBuffer);

	 device->DrawMesh(curmesh, shadowShader, depthBuffer);
	 device->DrawMesh(plane, shadowShader, depthBuffer);
	 device->DrawMesh(curmesh, phongShader, zBuffer);
	 device->DrawMesh(plane, planeShader, zBuffer);

	 BitBlt(window->hdc, 0, 0, windowWidth, windowHeight, window->screenHdc, 0, 0, SRCCOPY);
 }
 void FPS(Window* window) {
	 static float fps = 0;
	 static int frameCnt = 0;
	 static float curTime = 0.0f;
	 static float lastTime = 0.0f;
	 frameCnt++;
	 curTime = timeGetTime() * 0.001f;
	 if (curTime - lastTime > 1.0f) { 
		 fps = (float)frameCnt / (curTime - lastTime);
		 lastTime = curTime;
		 frameCnt = 0;
	 }
	 char str[20];
	 sprintf_s(str, 20, "%0.3f", fps);
	 TextOut(window->hdc, 0, 0, str, 6);
	 

 }
 void Cube() {
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	curmesh->AddVertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	curmesh->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	curmesh->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	curmesh->AddVertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vec4f(0, 0, -1), Color(1, 0, 0, 1));
	 
	curmesh->AddVertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	curmesh->AddVertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	curmesh->AddVertex(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	curmesh->AddVertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vec4f(0, 0, 1), Color(0, 1, 0, 1));
	 
	curmesh->AddVertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(-1, 0, 0));
	curmesh->AddVertex(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(-1, 0, 0));
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(-1, 0, 0));
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(-1, 0, 0));
	curmesh->AddVertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vec4f(-1, 0, 0));
	curmesh->AddVertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(-1, 0, 0));
	
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	curmesh->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	curmesh->AddVertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	curmesh->AddVertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	curmesh->AddVertex(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(1, 0, 0), Color(0, 0, 1, 1));
	 
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	curmesh->AddVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	curmesh->AddVertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	curmesh->AddVertex(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	curmesh->AddVertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	curmesh->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, -1, 0), Color(1, 1, 0, 1));
	 
	curmesh->AddVertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, 1, 0));
	curmesh->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, 1, 0));
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(0, 1, 0));
	curmesh->AddVertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vec4f(0, 1, 0));
	curmesh->AddVertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, Vec4f(0, 1, 0));
	curmesh->AddVertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, 1, 0));

 }
 void Plane() {
	 plane->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));
	 plane->AddVertex(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));
	 plane->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));
	 plane->AddVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));
	 plane->AddVertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));
	 plane->AddVertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vec4f(0, 0, 1), Color(1, 1, 1, 1));

	 Matrix pm;
	 Matrix s = mesh->GetTransform().Scale(Vec4f(5, 5, 5));
	 Matrix r = mesh->GetTransform().Rotate(Vec4f(0, 0, 0));
	 Matrix t = mesh->GetTransform().Translate(Vec4f(0, 0, -5));

	 pm = t * r * s;

	 planeShader->vert.m = pm;
	 plane->SetObjectToWorld(pm);
 }






